//
// Created by feng on 19-4-15.
//

/**
 * 目前只有：Cylinder rev + rectangle helio + rectangle grid
 * 其他类型仍然需要补充-----看懂算法+写过来
 */
#include <cuda_runtime.h>

#include <algorithm/rayTracing/qmcrt_util/check_cuda.h>
#include <algorithm/rayTracing/qmcrt_util/global_function.cuh>

#include "CylinderReceiverRectangleGridRayTracing.cuh"
#include "MultiPanelRectangleGridRayTracing.cuh"
#include "QuasiMonteCarloRayTracer.h"
#include "RectangleReceiverRectangleGridRayTracing.cuh"
#include "RefinedCylinderReceiverRectangleGridRayTracing.cuh"
#include "RefinedRectangleReceiverRectangleGridRayTracing.cuh"

#include <algorithm/analytical_model/algorithm/cuda/receiver/RectangleReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/grid/CudaRectangleGrid.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/heliostat/CudaHeliostat.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRectangleReceiver.cuh>
#include <algorithm/shared/tool/randomNumberGenerator/RandomGenerator.cuh>

#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaMultiPanelReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRefinedCylinderReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaRefinedRectangleReceiver.cuh>

#include <algorithm/rayTracing/dataLoader/SceneField.h>
#include <algorithm/rayTracing/rayTracingDataStructure/receiver/CudaCylinderReceiver.cuh>
#include <algorithm/rayTracing/rayTracingDataStructure/sunRay/CudaSunRay.cuh>

#include <numbers>

using namespace solar;
using namespace solar::cuda;

/**
 * 注意：：这里所有的坐标系均为y朝上，x向右，z向前
 */

void QuasiMonteCarloRayTracer::rayTracingViaField(std::shared_ptr<SceneField> field,
                                                  int heliostat_nums,
                                                  float3* d_subHeliostat_vertexe, bool res,
                                                  CloudLoader* cloud)
{
    /**
     * 获取相应的helio、grid、rev、sunray等data structure
     * -----通过field获得，注意只有一个helio
     */
    // std::cout << "QuasiMonteCarloRayTracer::rayTracingViaField(): get data from helio and
    // grid\n";

    auto sunray = field->getSunRay();
    // std::cout << "sunray\n";
    auto helio = field->getHeliostats()[0];
    // std::cout << "getHeliostats()[0]\n";
    int grid_id = helio->getBelongingGridId();
    // std::cout << "grid_id = " << grid_id << std::endl;
    // std::cout << "getBelongingGridId\n";

    // std::cout << "grid_id = " << grid_id;
    auto grid = field->getGrids()[grid_id];
    // std::cout << "getGrid\n";
    int rev_id = grid->getBelongingReceiverIndex();
    // std::cout << "getBelongingReceiverIndex\n";
    auto rev = field->getReceivers()[rev_id];
    // std::cout << "getReceivers()[rev_id]\n";

    /**
     *
     */
    // std::cout << "QuasiMonteCarloRayTracer::rayTracingViaField(): store data in SunrayArgument
    // and "
    //              "HeliostatArgument \n";
    float3 helio_size = helio->getSize();        // 定日镜的长宽高
    float helio_pixel = helio->getPixelLength(); // 微定日镜的边长
    float2 subhelio_row_col_length;              // 子定日镜的长和宽
    subhelio_row_col_length.x =
        (helio->size_.z - helio->gap_.y * (helio->row_col_.x - 1)) / float(helio->row_col_.x);
    subhelio_row_col_length.y =
        (helio->size_.x - helio->gap_.x * (helio->row_col_.y - 1)) / float(helio->row_col_.y);

    // std::cout << "====== helio->size = (" << helio->size_.x << "," << helio->size_.y << ","
    //           << helio->size_.z << ")" << std::endl;
    // std::cout << "====== helio->gap = (" << helio->gap_.x << "," << helio->gap_.y << ")"
    //           << std::endl;
    // std::cout << "====== helio->row_col_ = (" << helio->row_col_.x << "," << helio->row_col_.y
    //           << ")" << std::endl;

    // std::cout << "   subhelio_row_col_length = " << subhelio_row_col_length.x << " ,"
    //           << subhelio_row_col_length.y << std::endl;

    int2 micro_row_col_per_sub; // 一个子定日镜划分的微定日镜的行数、列数
    micro_row_col_per_sub.x = subhelio_row_col_length.x / helio->pixel_length_;
    micro_row_col_per_sub.y = subhelio_row_col_length.y / helio->pixel_length_;
    // std::cout << "======pixel_length_ = " << helio->pixel_length_ << std::endl;
    // std::cout << "    micro_row_col_per_sub = " << micro_row_col_per_sub.x << " ,"
    //           << micro_row_col_per_sub.y << std::endl;

    int micro_nums_per_sub =
        micro_row_col_per_sub.x * micro_row_col_per_sub.y; // 一个子定日镜上微定日镜个数
    int micro_nums_per_helio =
        helio->row_col_.x * helio->row_col_.y *
        micro_nums_per_sub; // 一个定日镜上微定日镜个数（helio->row_col_是定日镜上子定日镜的行数和列数）
    int subheliostat_nums =
        helio->row_col_.x * helio->row_col_.y * heliostat_nums; // 整个场景中子定日镜的个数

    SunrayArgument sunray_argument = generateSunrayArgument(
        sunray); // 光线跟踪过程中用到的太阳参数,这些参数集中在SunrayArgument中
    // std::cout <<"--------------------test sunrayArgument------------------\n";
    // int pool_size = sunrayArgument.pool_size;
    // std::cout << "pool size = "<<pool_size<<" umberOfLightsPerGroup = " <<
    // sunrayArgument.numberOfLightsPerGroup <<"\n"
    //             << "sunray_dir = "<<sunrayArgument.sunray_direction.x
    //             <<","<<sunrayArgument.sunray_direction.y <<","<<sunrayArgument.sunray_direction.z
    //             <<"\n";
    // float3 *samplelights = sunrayArgument.d_samplelights ;
    // float3 *pertuation = sunrayArgument.d_perturbations ;
    // for(int i=0 ; i<8 ; i++)
    // {
    //     std::cout << "samplelights "<<i<<" = "<< samplelights[i].x << "," << samplelights[i].y <<
    //     ","<<samplelights[i].z << "," << std::endl;
    // }
    // for(int i=0 ; i<8 ; i++)
    // {
    //     std::cout << "pertuation "<<i<<" = "<< pertuation[i].x << "," << pertuation[i].y << ","
    //     << pertuation[i].z << "," << std::endl;
    // }

    /**
     * 问题：heliostatArgument中的参数没有设置：heliostatArgument.helionums，heliostatArgument.micronums
     */
    // std::cout << "   rayTracingViaField()::micro_nums_per_helio=" << micro_nums_per_helio
    //           << "  micro_nums_per_sub=" << micro_nums_per_sub << std::endl;
    HeliostatArgument heliostat_argument =
        generateRectHelio(field, subheliostat_nums, micro_nums_per_sub); // 只有一个定日镜上的参数

    /**
     * TODO: except the type of rev and grid, type of helio should be added.
     */

    /**
     * 根据receiver和grid的类型进入不同的.cu文件
     */
    // std::cout << "QuasiMonteCarloRayTracer::rayTracingViaField(): choose next raytracing function
    // "
    //              "based on type of rev & grid \n";
    int receiver_grid_combination_index = receiverGridCombination(
        rev->getType(), grid->getGridType()); // 根据rev和grid类型生成一个index，用于switch
    switch (receiver_grid_combination_index)
    {
    /**
     * rectangle rev + rectangle grid
     */
    case 0:
    {
        // std::cout
        //     << "----------------- in switch---rectangle rev + rectangle grid --------------\n";
        auto* rectangle_rev = dynamic_cast<CudaRectangleReceiver*>(rev.get());
        auto* rectangle_grid = dynamic_cast<CudaRectangleGrid*>(grid.get());

        float ratio = helio->getPixelLength() / rev->getPixelLength();
        float factor =
            sunray->getDNI() * ratio * ratio *
            sunray
                ->getReflectiveRate() // 这里要计算每根光线上带的能量（这里乘了反射率，没有大气衰减系数和cos
                                      // phi）
            / float(sunray->getNumOfSunshapeLightsPerGroup());

        RectangleReceiverRectangleGridRayTracing(&sunray_argument, rectangle_rev, rectangle_grid,
                                                 &heliostat_argument, d_subHeliostat_vertexe,
                                                 factor, res, cloud, stream_);

        break;
    }

    /* cylinder rev + rectangle grid
     */
    case 10:
    {
        // std::cout
        //     << "---------------------- in switch---cylinder rev + rectangle grid ------------\n";
        auto* cylinder_rev = dynamic_cast<CudaCylinderReceiver*>(rev.get());
        auto* rectangle_grid = dynamic_cast<CudaRectangleGrid*>(grid.get());

        float ratio = helio->getPixelLength() / rev->getPixelLength();
        float factor =
            sunray->getDNI() * ratio * ratio *
            sunray
                ->getReflectiveRate() // 这里要计算每根光线上带的能量（这里乘了反射率，没有大气衰减系数和cos
                                      // phi）
            /
            float(
                sunray
                    ->getNumOfSunshapeLightsPerGroup()); // 没有乘以cos(phi)------每个微定日镜的法向都不一样，要在光追内部乘
                                                         // 没有乘大气衰减系数------大气衰减与光线发出点到接收器的距离有关
                                                         // 关于反射率-----lin的论文中没有写反射率，duan的论文中写了（再看一下两篇论文）
        printf("factor = %f * %f * %f * %f / %f\n", sunray->getDNI(), ratio, ratio,
               sunray->getReflectiveRate(), float(sunray->getNumOfSunshapeLightsPerGroup()));
        std::cout << "======= factor = " << factor << std::endl;
        std::cout << "  about to enter func: cylinderREceiverRectangleGridRayTracing()\n";
        CylinderReceiverRectangleGridRayTracing(&sunray_argument, cylinder_rev, rectangle_grid,
                                                &heliostat_argument, d_subHeliostat_vertexe, factor,
                                                res, cloud);
        //      光线                接收器          grid            helio           子定日镜的顶点
        //      factor-预先计算出的一根光线的能量（还没乘以cos(phi) ）
        break;
    }

    /**
     * refined rectangle rev + rectangle grid
     */
    case 20:
    {
        // std::cout << "---------------------- in switch- refined rectangle rev + rectangle grid "
        //              "------------\n";

        auto* refined_rectangle_rev = dynamic_cast<CudaRefinedRectangleReceiver*>(rev.get());
        auto* rectangle_grid = dynamic_cast<CudaRectangleGrid*>(grid.get());

        float ratio = helio->getPixelLength() / rev->getPixelLength();
        float factor = sunray->getDNI() * ratio * ratio * sunray->getReflectiveRate() /
                       float(sunray->getNumOfSunshapeLightsPerGroup());

        RefinedRectangleReceiverRectangleGridRayTracing(&sunray_argument, refined_rectangle_rev,
                                                        rectangle_grid, &heliostat_argument,
                                                        d_subHeliostat_vertexe, factor, res, cloud);

        break;
    }

    /**
     * refined cylinder rev + rectangle grid
     */
    case 30:
    {
        // std::cout << "---------------------- in switch- refined cylinder rev + rectangle grid "
        //              "------------\n";

        auto* refined_cylinder_rev = dynamic_cast<CudaRefinedCylinderReceiver*>(rev.get());
        auto* rectangle_grid = dynamic_cast<CudaRectangleGrid*>(grid.get());

        int tube_unit = rev->getTubeUnit();
        float theta = MATH_PI / tube_unit; // ？？？？？半圆上分为tube_unit个单元
        float r = rev->getRadius();
        float l = theta * r; // 吸热管圆周上一个单位对应的弧长
        float h = rev->getSize().y;
        h = h / rev->getResolution().y; // 纵向上一个单位的长度
        float rev_pixel = h * l;        // 接收器一个pixel的面积
        float ratio = helio->getPixelLength() * helio->getPixelLength() /
                      rev_pixel; // 这里就是helio和rev的pixel的面积的比值
        float factor = sunray->getDNI() * ratio * sunray->getReflectiveRate() /
                       float(sunray->getNumOfSunshapeLightsPerGroup());

        RefinedCylinderReceiverRectangleGridRayTracing(&sunray_argument, refined_cylinder_rev,
                                                       rectangle_grid, &heliostat_argument,
                                                       d_subHeliostat_vertexe, factor, res, cloud);

        break;
    }

    /**
     * multi panel rev + rectangle grid
     */
    case 40:
    {
        // std::cout
        //     << "---------------------- in switch- multi panel rev + rectangle grid ------------\n";

        auto* multipanel_rev = dynamic_cast<CudaMultiPanelReceiver*>(rev.get());
        auto* rectangle_grid = dynamic_cast<CudaRectangleGrid*>(grid.get());

        float dis = 2 * rev->getSize().x * std::sin(std::numbers::pi_v<float> / rev->getPanel());
        float l = dis / rev->getTube() / 2;
        float h = rev->getSize().y;
        h = h / rev->getResolution().y;
        float rev_pixel = h * l;
        float ratio = helio->getPixelLength() * helio->getPixelLength() / rev_pixel;
        float factor = sunray->getDNI() * ratio * sunray->getReflectiveRate() /
                       float(sunray->getNumOfSunshapeLightsPerGroup());
        MultiPanelReceiverRectangleGridRayTracing(sunray_argument, multipanel_rev, rectangle_grid,
                                                  heliostat_argument, d_subHeliostat_vertexe,
                                                  factor, res, cloud);

        break;
    }
    }
}

auto QuasiMonteCarloRayTracer::generateSunrayArgument(const std::shared_ptr<cuda::CudaSunray>& sunray)
    -> SunrayArgument
{
    // SunrayArgument(float3 *samplelights, float3 *perturbations, int pool_size_, int
    // lightsPerGroup, float3 sunray_dir)
    // std::cout << "------------sunray.sun_direction = " << sunray->getSunDirection().x << ","
    //           << sunray->getSunDirection().y << "," << sunray->getSunDirection().z << std::endl;
    return {sunray->getDeviceSampleLights(), // float3 *samplelights
            sunray->getDevicePerturbation(), // float3 *perturbations
            sunray->getNumOfSunshapeGroups() *
                sunray->getNumOfSunshapeLightsPerGroup(), // pool_size_
            sunray->getNumOfSunshapeLightsPerGroup(),     // int lightsPerGroup
            sunray->getSunDirection()};                   // float3 sunray_dir
}

auto QuasiMonteCarloRayTracer::generateRectHelio(std::shared_ptr<SceneField> field,
                                                 int subheliostat_nums,
                                                 int micro_nums_per_sub) const -> HeliostatArgument
{
    int* h_subhelio_id = new int[subheliostat_nums]; // 把sub id存放在cpu的数组中 ---
                                                     // 这里是整个场景中的全部子定日镜的id
    for (int sub_helio_id = 0; sub_helio_id < subheliostat_nums; sub_helio_id++)
    { // 在h_subhelio_id中存入微定日镜的id---其实就是0 ~ subheliostat_nums-1
        h_subhelio_id[sub_helio_id] = sub_helio_id;
    }
    int* d_subhelio_id = nullptr; // 把微定日镜的id存到GPU中
    checkCudaErrors(cudaMallocAsync((void**)&d_subhelio_id, sizeof(int) * subheliostat_nums,
                                    stream_)); // 给micro id数组在GPU上分配空间
    checkCudaErrors(cudaMemcpyAsync(d_subhelio_id, h_subhelio_id, sizeof(int) * subheliostat_nums,
                                    cudaMemcpyHostToDevice, stream_)); // 从CPU上把数组内容复制过去

    auto helio = field->getHeliostats()[0];
    float3 size = helio->getSize();

    int row = helio->getRowAndColumn().x; // 每个helio上sub的行数
    int col = helio->getRowAndColumn().y; // 每个helio上sub的列数
    float2 gap = helio->getGap();
    float pixel = helio->getPixelLength();
    float2 subhelio_row_col_length; // 子定日镜在两个方向上的长度
    subhelio_row_col_length.x = (size.z - gap.y * (row - 1)) / float(row);
    subhelio_row_col_length.y = (size.x - gap.x * (col - 1)) / float(col);
    //    cout << "subhelio_row_col_length----------" << subhelio_row_col_length.x << ", " <<
    //    subhelio_row_col_length.y << endl;
    float sizex = subhelio_row_col_length.x;
    float sizey = size.y;
    float sizez =
        subhelio_row_col_length
            .y; // sizex，sizey，sizez表示子定日镜在三个维度上的尺寸(sub的厚度与helio的厚度相等)

    int2 micro_row_col_per_sub; // 每个子定日镜上微定日镜的行数、列数
    micro_row_col_per_sub.x = int(subhelio_row_col_length.x / pixel);
    micro_row_col_per_sub.y = int(subhelio_row_col_length.y / pixel);
    // 每个子定日镜有多少微定日镜

    // std::cout << "   generateRectHelio()::subheliostat_nums = " << subheliostat_nums
    //           << "  micro_nums_per_sub = " << micro_nums_per_sub << std::endl
    //           << "       micro_row_col_per_sub = (" << micro_row_col_per_sub.x << ","
    //           << micro_row_col_per_sub.y << ")" << std::endl
    //           << "       pixel = " << pixel << "  sizex = " << sizex << "  sizey = " << sizey
    //           << "  sizez = " << sizez << std::endl;

    return {subheliostat_nums,
            micro_nums_per_sub,
            micro_row_col_per_sub.x,
            micro_row_col_per_sub.y,
            pixel,
            sizex,
            sizey,
            sizez,
            d_subhelio_id};
}

// void QuasiMonteCarloRayTracer::rayTracing_(SolarScene *solarScene, int subheliostat_nums,float3
// *d_subHeliostat_vertexe,bool res, CloudLoader *cloud){
//     /**
//      * check valid heliostat index
//      */
//     //checkValidHeliostatIndex(solarScene, heliostat_id);

//     /**
//      * Data Structure
//      */
//     //  -sunray
//     Sunray *sunray = solarScene->getSunray();
//     //  -heliostat
//     Heliostat *heliostat = solarScene->getHeliostats()[0];
//     //int helio
//     //  -grid
//     int grid_id = heliostat->getBelongingGridId();
//     Grid *grid = solarScene->getGrids()[grid_id];
//     //  -receiver
//     int receiver_id = grid->getBelongingReceiverIndex();
//     Receiver *receiver = solarScene->getReceivers()[receiver_id];

//     /**
//      * Construct the sub_heliostat vertexes array
//      */
//     float3 helio_size=heliostat->getSize();
//     float helio_pixel=heliostat->getPixelLength();
//     float2 subhelio_row_col_length;
//     subhelio_row_col_length.x = (heliostat->size_.z - heliostat->gap_.y * (heliostat->row_col_.x
//     - 1)) / float(heliostat->row_col_.x); subhelio_row_col_length.y = (heliostat->size_.x -
//     heliostat->gap_.x * (heliostat->row_col_.y - 1)) / float(heliostat->row_col_.y);

//     int2 sub_row_col;
//     sub_row_col.x = subhelio_row_col_length.x / heliostat->pixel_length_;
//     sub_row_col.y = subhelio_row_col_length.y / heliostat->pixel_length_;

//     int map_size = sub_row_col.x * sub_row_col.y * heliostat->row_col_.x * heliostat->row_col_.y;
// //    int micro_nums=(int)(helio_size.x*helio_size.z/helio_pixel/helio_pixel);
//     int micro_nums=sub_row_col.x * sub_row_col.y;

//     int subhelionums=heliostat->row_col_.x * heliostat->row_col_.y*subheliostat_nums;
// //    printf("subhelio %d micro_nums %d\n",subhelionums,micro_nums);

//     SunrayArgument sunrayArgument = generateSunrayArgument(sunray);//光线跟踪过程中用到的太阳参数
//     HeliostatArgument heliostatArgument = generateRectHelio(solarScene, subhelionums,micro_nums);
//     //heliostatArgument 保存所有定日镜的坐标、法向、id

//     //光线跟踪过程中用到的定日镜相关参数       把所有为定日经信息放在其中
//     int receiverGridCombinationIndex = receiverGridCombination(receiver->getType(),
//     grid->getGridType());

//     switch(receiverGridCombinationIndex){
//         case 0:{
//             /** RectangleReceiver & RectangleGrid*/
//             auto rectangleReceiver = dynamic_cast<RectangleReceiver *>(receiver);
//             auto rectangleGrid = dynamic_cast<RectangleGrid *>(grid);

//             float ratio = heliostat->getPixelLength() / receiver->getPixelLength();
//             float factor = sunray->getDNI() * ratio * ratio * sunray->getReflectiveRate()
//                            / float(sunray->getNumOfSunshapeLightsPerGroup());
//             RectangleReceiverRectangleGridRayTracing(sunrayArgument, rectangleReceiver,
//             rectangleGrid, heliostatArgument, d_subHeliostat_vertexe,factor,res,cloud);

//             break;
//         }
//         case 10:{
//             /** CylinderReceiver & RectangleGrid*/
//             auto cylinderReceiver = dynamic_cast<CylinderReceiver *>(receiver);
//             auto rectangleGrid = dynamic_cast<RectangleGrid *>(grid);
// /*             auto start_time = std::chrono::high_resolution_clock::now();
//              auto end_time = start_time;
//              long long elapsed;*/

//             float ratio = heliostat->getPixelLength() / receiver->getPixelLength();
//             float factor = sunray->getDNI() * ratio * ratio * sunray->getReflectiveRate()
//                            / float(sunray->getNumOfSunshapeLightsPerGroup());

//             CylinderReceiverRectangleGridRayTracing(sunrayArgument,
//             cylinderReceiver,rectangleGrid,heliostatArgument,d_subHeliostat_vertexe,
//             factor,res,cloud);

// /*   end_time = std::chrono::high_resolution_clock::now();
//             elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end_time -
//             start_time).count();

//             std::cout << " heliostatArgument took " << elapsed << " microseconds to ray tracing."
//             << std::endl;*/

//             break;
//         }
//         case 20:{
//             /** RefinedRectangleReceiver & RectangleGrid*/
//             auto refinedRectangleReceiver = dynamic_cast<RefinedRectangleReceiver *>(receiver);
//             auto rectangleGrid = dynamic_cast<RectangleGrid *>(grid);

//             float ratio = heliostat->getPixelLength() / receiver->getPixelLength();
//             float factor = sunray->getDNI() * ratio * ratio * sunray->getReflectiveRate()
//                            / float(sunray->getNumOfSunshapeLightsPerGroup());

//             RefinedRectangleReceiverRectangleGridRayTracing(sunrayArgument,
//             refinedRectangleReceiver, rectangleGrid,
//                                                             heliostatArgument,
//                                                             d_subHeliostat_vertexe,
//                                                             factor,res,cloud);

//             break;
//         }
//         case 30:{
//             // RefinedCylinderReceiver & RectangleGrid

//             auto refinedCylinderReceiver = dynamic_cast<RefinedCylinderReceiver *>(receiver);
//             auto rectangleGrid = dynamic_cast<RectangleGrid *>(grid);
//             int tube_unit=receiver->tubeUnit_;
//             float theta=MATH_PI/tube_unit;
//             float r=receiver->radius_;
//             float l=theta*r;
//             float h =receiver->size_.y;
//             h=h/receiver->resolution_.y;
//             float rece_pixel=h*l;
//             float ratio = heliostat->getPixelLength() *heliostat->getPixelLength()/rece_pixel;
//             float factor = sunray->getDNI() * ratio * sunray->getReflectiveRate()
//                            / float(sunray->getNumOfSunshapeLightsPerGroup());
//             RefinedCylinderReceiverRectangleGridRayTracing(sunrayArgument,
//             refinedCylinderReceiver, rectangleGrid,
//                                                            heliostatArgument,
//                                                            d_subHeliostat_vertexe,
//                                                            factor,res,cloud);

//             break;
//         }
//         case 40:{
//             // Multipanel & RectangleGrid

//             auto multiPanelReceiver = dynamic_cast<MultiPanelReceiver *>(receiver);
//             auto rectangleGrid = dynamic_cast<RectangleGrid *>(grid);

//             float Dis=2*receiver->size_.x* sin(std::numbers::pi_v<float>/receiver->panel_);
//             float l=Dis/receiver->tube_/2;
//             float h =receiver->size_.y;

//             h=h/receiver->resolution_.y;
//             std::cout<<Dis<<" l:"<<l<<" h:"<<h<<std::endl;
//             float rece_pixel=h*l;
//             float ratio = heliostat->getPixelLength() *heliostat->getPixelLength()/rece_pixel;
//             float factor = sunray->getDNI() * ratio * sunray->getReflectiveRate()
//                            / float(sunray->getNumOfSunshapeLightsPerGroup());
//             MultiPanelReceiverRectangleGridRayTracing(sunrayArgument, multiPanelReceiver,
//             rectangleGrid,
//                                                            heliostatArgument,
//                                                            d_subHeliostat_vertexe,
//                                                            factor,res,cloud);

//             break;
//         }
//             /**
//              * TODO: Add other branch for different type of receiver or grid.
//              */

//         default:
//             break;
//     }

//     //heliostatArgument.CClear();
// }
// /**
//  *  Public following function just for test. Do not use them standalone.
//  */
// void QuasiMonteCarloRayTracer::checkValidHeliostatIndex(SolarScene *solarScene, int
// heliostat_id){
//     std::string error_message;
//     std::string suffix = " is invalid.";

//     // 1. Valid heliostat id
//     error_message = "The ray tracing heliostat index " + std::to_string(heliostat_id);
//     size_t  total_heliostat = solarScene->getHeliostats().size();
//     if(heliostat_id < 0 || heliostat_id >= total_heliostat){
//         std::string total_heliostat_message = "The heliostat index should between 0 and " +
//         std::to_string(total_heliostat) + "."; throw std::runtime_error(error_message + suffix +
//         total_heliostat_message);
//     }
//     Heliostat *heliostat = solarScene->getHeliostats()[heliostat_id];

//     // 2. Valid grid id
//     int grid_id = heliostat->getBelongingGridId();
//     error_message += "with belonging grid index " + std::to_string(grid_id);
//     size_t total_grid = solarScene->getGrids().size();
//     if(grid_id < 0 || grid_id >= total_grid){
//         std::string total_grid_message = "The grid index should between 0 and " +
//         std::to_string(total_grid) + "."; throw std::runtime_error(error_message + suffix +
//         total_grid_message);
//     }
//     Grid *grid = solarScene->getGrids()[grid_id];

//     // 3. Valid receiver id
//     int receiver_id = grid->getBelongingReceiverIndex();
//     error_message += "of belonging receiver index " + std::to_string(receiver_id);
//     size_t total_receivers = solarScene->getReceivers().size();
//     if(receiver_id < 0 || receiver_id >= total_receivers){
//         std::string total_receiver_message = "The receiver index should between 0 and " +
//         std::to_string(total_receivers) + "."; throw std::runtime_error(error_message + suffix +
//         total_receiver_message);
//     }
// }

// int QuasiMonteCarloRayTracer::receiverGridCombination(int receiver_type, int grid_type){
//     return receiver_type * 10 + grid_type;
// }

// HeliostatArgument QuasiMonteCarloRayTracer::generateHeliostatArguments(SolarScene *solarScene,
// int heliostat_nums,int map_size){
//     ///把所有定日经的微定日镜信息放在一个数组中

//     Heliostat *helio = solarScene->getHeliostats()[0];

//     //printf("map_size*heliostat_nums = %d \n",map_size*heliostat_nums);
//     float3 *d_microhelio_origins = nullptr;
//     checkCudaErrors(cudaMalloc((void **) &d_microhelio_origins, sizeof(float3) *
//     map_size*heliostat_nums));

//     float3 *d_microhelio_normals = nullptr;
//     checkCudaErrors(cudaMalloc((void **) &d_microhelio_normals, sizeof(float3) *
//     map_size*heliostat_nums));

//     int *d_microhelio_belonging_groups = nullptr;
//     int pool_size = solarScene->getSunray()->getNumOfSunshapeGroups() *
//                     solarScene->getSunray()->getNumOfSunshapeLightsPerGroup();
//     //printf("pool_size=%d,map_size=%d\n",pool_size,map_size);

// //heliostatArgument 需要微定日镜顶点、法向、所属
//     int numberOfMicrohelio;

//     int subhelio_size=0;
//     int *d_subheliostat_id= nullptr;
//     checkCudaErrors(cudaMalloc((void **) &d_subheliostat_id, sizeof(int) *heliostat_nums));
//     int *subheliostat_id=new int[heliostat_nums];

//     for(int heliostat_id=0;heliostat_id<heliostat_nums;heliostat_id++){

//         Heliostat *heliostat = solarScene->getHeliostats()[heliostat_id];
//         //printf("       here_4.4 ok\n");

//         heliostat->CGetDiscreteMicroHelioOriginsAndNormals_(d_microhelio_origins,
//         d_microhelio_normals,heliostat_id);
//         //printf("       here_5 ok\n");

//         Grid *grid = solarScene->getGrids()[heliostat->getBelongingGridId()];
//         int subHeliostat_id = 0;
//         for(int i = 0; i < grid->getNumberOfHeliostats(); ++i){
//             int real_id = i + grid->getStartHeliostatIndex();
//             if(real_id == heliostat_id)
//                 break;

//             Heliostat *before_heliostat = solarScene->getHeliostats()[real_id];
//             subHeliostat_id += before_heliostat->getSubHelioSize();
//         }
//         //printf("       here_6 ok\n");

//         subhelio_size+=heliostat->getSubHelioSize();
//         //printf("       here_7 ok\n");

//         subheliostat_id[heliostat_id]=subHeliostat_id;
// //        printf("    %d   here_8 ok\n",heliostat_id);

//     }
//     global_func::cpu2gpu(d_subheliostat_id, subheliostat_id, heliostat_nums);

// //    printf("       here_7 ok\n");

//     numberOfMicrohelio=map_size*heliostat_nums;

//     d_microhelio_belonging_groups = helio->generateDeviceMicrohelioGroup(pool_size,
//     numberOfMicrohelio);
// //    printf("子丁日镜个数 %d\n",subhelio_size);
//     //return HeliostatArgument(d_microhelio_origins, d_microhelio_normals,
//     d_microhelio_belonging_groups,
//      //                        numberOfMicrohelio, d_subheliostat_id, subhelio_size);
// }

// HeliostatArgument QuasiMonteCarloRayTracer::generateRectHelio(SolarScene *solarScene, int
// subhelionums,int micronums){
//     ///把所有定日经的微定日镜信息放在一个数组中
//    // HeliostatArgument 需要的参数：
// //    float3 *d_microHelio_origins;  微定日镜中点
// //    float3 *d_microHelio_normals;  微定日镜法向
// //    int *d_microHelio_groups;      微定日镜采样随机数（0～1024）每个微定日镜一个
// //    int numberOfMicroHeliostats;   微定日镜个数
// //    int *subHeliostat_id;          子定日镜id
// //    int numberOfSubHeliostats;     子定日镜个数

// //微丁日经中点 需要每个定日镜的坐标
// //微丁日经中点 需要每个定日镜的法向
// //需要在这个函数把定日镜的中点读到global memory 新建数组  vector -> cpu array -> gpu array
// //heliostat 的法向读到global memory 新建数组   vector ->cpu array -> gpu array
// //   float3 *h_heliostat_pos=new float3[subhelionums];
// //   float3 *h_heliostat_normal=new float3[subhelionums];
//     int *h_subhelio_id=new int[subhelionums];

//     for(int heliostat_id=0;heliostat_id<subhelionums;heliostat_id++) {

//         h_subhelio_id[heliostat_id]=heliostat_id;
//     }

//     int *d_subheliostat_id= nullptr;
//     checkCudaErrors(cudaMalloc((void **) &d_subheliostat_id, sizeof(int) *subhelionums));
//     checkCudaErrors(cudaMemcpy(d_subheliostat_id,h_subhelio_id,sizeof(int)*subhelionums,cudaMemcpyHostToDevice));

//     Heliostat *helio = solarScene->getHeliostats()[0];
//     float3 size=helio->getSize();

//     int row=helio->getRowAndColumn().x;
//     int col=helio->getRowAndColumn().y;
//     float2 gap=helio->getGap();
//     float pixel=helio->getPixelLength();
//     float2 subhelio_row_col_length;
//     subhelio_row_col_length.x = (size.z - gap.y * (row- 1)) / float(row);
//     subhelio_row_col_length.y = (size.x - gap.x * (col - 1)) / float(col);
// //    cout << "subhelio_row_col_length----------" << subhelio_row_col_length.x << ", " <<
// subhelio_row_col_length.y << endl;
//     float sizex=subhelio_row_col_length.x;
//     float sizey=size.y;
//     float sizez=subhelio_row_col_length.y;
//     //子定日镜的size
//     int2 sub_row_col;
//     sub_row_col.x = int(subhelio_row_col_length.x / pixel);
//     sub_row_col.y = int(subhelio_row_col_length.y / pixel);
//     //每个子定日镜有多少微定日镜

//     return
//     HeliostatArgument(subhelionums,micronums,sub_row_col.x,sub_row_col.y,pixel,sizex,sizey,sizez,d_subheliostat_id);
// }
// SunrayArgument QuasiMonteCarloRayTracer::generateSunrayArgument(Sunray *sunray){
//     // SunrayArgument(float3 *samplelights, float3 *perturbations, int pool_size_, int
//     lightsPerGroup, float3 sunray_dir) return SunrayArgument(sunray->getDeviceSampleLights(),
//     //float3 *samplelights
//                           sunray->getDevicePerturbation(),          //float3 *perturbations
//                           sunray->getNumOfSunshapeGroups() *
//                           sunray->getNumOfSunshapeLightsPerGroup(),    //pool_size_
//                           sunray->getNumOfSunshapeLightsPerGroup(), //int lightsPerGroup
//                           sunray->getSunDirection());               //float3 sunray_dir
// }

// /**
//  *
//  * @param d_heliostat_vertexs : SubHeliostat vertexes
//  * @param heliostats
//  * @param start_id
//  * @param end_id
//  * @return the number of subHeliostats
//  */
// int QuasiMonteCarloRayTracer::setFlatRectangleHeliostatVertexs(float3 *&d_heliostat_vertexs,
// std::vector<Heliostat *> &heliostats,
//                                                                 int start_id, int end_id){
//     if(start_id < 0 || start_id > end_id || end_id > heliostats.size()){
//         throw std::runtime_error(__FILE__ ". The index " + std::to_string(start_id) + " and " +
//         std::to_string(end_id) + " is invalid.");
//     }

//     // clean up d_heliostat_vertexes
//     if(d_heliostat_vertexs != nullptr){
//         checkCudaErrors(cudaFree(d_heliostat_vertexs));
//         d_heliostat_vertexs = nullptr;
//     }

//     std::vector<float3> subHeliostatVertexes;
//     for(int i = start_id; i < end_id; ++i){
//         //printf("start_id=%d  第%d个自定日镜  end_id=%d\n",start_id,i,end_id);
//         heliostats[i]->CGetSubHeliostatVertexes(subHeliostatVertexes);
//     }

//     float3 *h_subHeliostat_vertexes = new float3[subHeliostatVertexes.size()];
//     for(int i = 0; i < subHeliostatVertexes.size(); ++i){
//         h_subHeliostat_vertexes[i] = subHeliostatVertexes[i];
//     }

//     global_func::cpu2gpu(d_heliostat_vertexs, h_subHeliostat_vertexes,
//     subHeliostatVertexes.size()); delete[] h_subHeliostat_vertexes; h_subHeliostat_vertexes =
//     nullptr;

//     return subHeliostatVertexes.size();
// }
